package org.liubility.robot.handler.base;

import lombok.Builder;
import lombok.Data;
import lombok.SneakyThrows;
import net.mamoe.mirai.contact.Contact;
import net.mamoe.mirai.event.SimpleListenerHost;
import net.mamoe.mirai.event.events.MessageEvent;
import org.liubility.robot.annotation.OrderMapping;
import org.liubility.robot.untils.OrderUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: Jdragon
 * @email: 1061917196@qq.com
 * @Date: 2020.10.24 22:26
 * @Description:
 */
public class BaseHandler extends SimpleListenerHost {

    private final Map<String, Order> orderMethodMap = new HashMap<>();

    private final List<Order> allOrderMethodList = new ArrayList<>(); //无映射指令的方法，代表任意指令执行

    private final String split = "#";

    public BaseHandler() {
        Class<? extends BaseHandler> aClass = this.getClass();
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            if (!method.isAnnotationPresent(OrderMapping.class))
                continue;
            OrderMapping orderMapping = method.getAnnotation(OrderMapping.class);
            String orderStr = orderMapping.value();
            Order order = Order.builder()
                    .order(orderStr)
                    .reply(orderMapping.reply())
                    .methodName(method.getName()).build();

            //无映射指令的方法，代表任意指令执行
            if (orderStr.isEmpty()) {
                allOrderMethodList.add(order);
            } else {
                orderMethodMap.put(split + orderStr, order);
            }

        }
    }

    public void invoke(MessageEvent event) {
        String message = event.getMessage().contentToString();

        String orderStr = OrderUtils.findOrder(message);

        if (orderStr == null && allOrderMethodList.isEmpty()) {
            return;
        }

        orderStr = split + orderStr;

        if (orderMethodMap.containsKey(orderStr)) {
            Order order = orderMethodMap.get(orderStr);
            this.invoke(order, event);
        } else {
            for (Order order : allOrderMethodList) {
                this.invoke(order, event);
            }
        }
    }

    @SneakyThrows
    private void invoke(Order order, MessageEvent event) {
        Contact subject = event.getSubject();
        String methodName = order.getMethodName();
        Method method = this.getClass().getDeclaredMethod(methodName, MessageEvent.class);
        method.setAccessible(true);
        Object invoke = method.invoke(this, event);
        method.setAccessible(false);
        //需要程序自动回复
        if (order.isReply()) {
            String replyStr = String.valueOf(invoke);
            subject.sendMessage(replyStr);
        }
    }

    @Data
    @Builder
    static class Order {
        private String order;

        private String methodName;

        private boolean reply;
    }
}
